
/*
 * Handles page seeds, filters potential seeds
 * 
 */

package managers;

import java.net.URI;
import java.util.LinkedList;
import java.util.NoSuchElementException;

import core.Config;
import database.SqlManager;

public class SeedHandler extends Thread 
{
	private static SeedHandler mInstance;
	
	private LinkedList <URI> mValidateQueue;
	private LinkedList <URI> mSeedQueue;
	
	private volatile boolean mRunning = true;


	private SeedHandler()
	{	
		mSeedQueue = new LinkedList<URI>();
		mValidateQueue = new LinkedList<URI>();
	}
	
	public static SeedHandler getInstance()
	{
		if (mInstance != null)
			return mInstance;
		else
		{
			mInstance = new SeedHandler();
			return mInstance;
		}
	}
	
	/* get size of seed queue awaiting validation */
	public int getValidateQueueSize()
	{
		synchronized ( mValidateQueue )
		{
			return mValidateQueue.size();
		}
	}
	
	/* get size of seed queue that have been validated */
	public int getSeedQueueSize()
	{
		synchronized ( mSeedQueue )
		{
			return mSeedQueue.size();
		}
	}
	
	/* stop seed process */
	public void stopProcess()
	{
		synchronized ( this )
		{
			mRunning = false;
			this.notify();
		}
	}
	
	/* add potential seed to validate queue */
	public boolean addValidateUrl( URI pageURL )
	{

		synchronized ( mValidateQueue )
		{
			if (mValidateQueue.size() < Config.VALIDATE_QUEUE_LIMIT)
			{
				return mValidateQueue.add( pageURL );
			}
			else
			{
				return false;
			}
		}
	}
	
	/* forces seed as validated */
	public boolean addForcedSeed( URI pageURL )
	{
		synchronized ( mSeedQueue )
		{
			return mSeedQueue.add( pageURL );
		}
		
	}
	
	
	/* Returns true if validate queue can transfer a URI to seed queue */
	private boolean canTransferValidateToSeed()
	{
		int seedsize, validatesize;

		synchronized (mSeedQueue)
		{
			seedsize = mSeedQueue.size();
		}
		
		synchronized (mValidateQueue)
		{
			validatesize = mValidateQueue.size();
		}
		
		if (seedsize < Config.SEED_QUEUE_LIMIT && validatesize > 0)
		{
			return true;
		}

		
		return false;
	}
	
	/* Gets seed from seed queue, notifies thread (called from another thread) */
	public URI getSeed()
	{
		URI url;
		synchronized (mSeedQueue)
		{
			try 
			{
				url = mSeedQueue.remove();
				while (!validateUrl(url))
				{
					url = mSeedQueue.remove();
				}
			}
			catch (NoSuchElementException e)
			{
				return null;
			}
		}
		
		
		synchronized (this )
		{
			try
			{
				this.notify();
			}
			catch (IllegalMonitorStateException e)
			{
			}
		}
		
		return url;
	}
	
	/* validates url, return true if url is a valid seed */
	private boolean validateUrl (URI url)
	{
		String baseUrl = url.getScheme() + "://" + url.getAuthority();
		
		if (SqlManager.getInstance().validateForSeeding(baseUrl))
		{
			return true;
		}
		
		return false;
	}
	
	
	/* handles validate to seed transfer, is called by current thread and represents it's main activity */
	private void handleValidateQueue()
	{
		while (canTransferValidateToSeed())
		{
			URI urlToBeValidated;
			synchronized (mSeedQueue)
			{
				synchronized (mValidateQueue)
				{				
					urlToBeValidated = mValidateQueue.remove();
				}
				
				if (validateUrl(urlToBeValidated))
				{
					mSeedQueue.add(urlToBeValidated);
				}
			}
			
		}
	}
	
	public void run ()
	{
		Thread.currentThread().setName("SEED HANDLER");
		while ( mRunning )
		{
			
			handleValidateQueue();
			
			try 
			{
				synchronized (this)
				{
					if (mRunning && !canTransferValidateToSeed())
					{
						this.wait(10000);
					}
				}
			} 
			catch (InterruptedException e) 
			{
				e.printStackTrace();
			}
		}
	}
}
